package TangramCore;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JPanel;

public class Obrazec extends JPanel implements MouseListener,MouseMotionListener,MouseWheelListener,/*ComponentListener,*/ KeyListener{
	static final long serialVersionUID = 24362462L;
	
    //static FileWriter f; //temp
    
    static final int POHYB_NIC = 0, POHYB_ROTACE = 1, POHYB_POSUN = 2, POHYB_ROTACE_WHEEL = 3, POHYB_FLIP = 4, POHYB_HLADINA_POSUN = 5;
    public static final int MOD_EDIT = 1, MOD_SHOW = 0, MOD_LAYOUT = 2;
    static final Cursor cur[] = {
        Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR),
        Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR),
        Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR),
        Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR),
        Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)
    };
    static final double /*TOLERANCE_PRISKOK = 1, ROTACE_KROK = 15 * Math.PI / 180,*/ ROTACE_CITLIVOST = 10;
    //static final int MODE_EDIT = 0, MODE_SOLVE = 1, MODE_VIEW = 2, MODE_PRINT = 3;
    
 /* private String FILE_MASS = "C:\\Projekty\\Tangram_java\\obrazce\\mass.obr";
  private String FILE_OBRAZEC = "C:\\Projekty\\Tangram_java\\obrazce\\obrazec.obr";
  private String FILE_SKLADACKA = "C:\\Projekty\\Tangram_java\\skladacky\\tangram.skl";
  private String FILE_IMAGE = "obrazky\\tblall.png";//"C:\\Projekty\\Tangram_java\\obrazky\\tblall.png";*/
    
    private int pohyb = POHYB_NIC;
    
    private java.awt.geom.Point2D drag = new java.awt.geom.Point2D.Double();
    private Point2D pivot = new Point2D();
    private Point last = new Point();
    
    private Dilek d[], dNahled[];
    private Obrys o; //[] = {new Obrys(), new Obrys()};
    
    protected Skladacka skladacka;
    Rectangle rectUpdate = new Rectangle();
    //Dilek dOrdered[];
    
//  private Dilek dVzor[];
//  private Obrys oVzor;
    
    private int vybrano = 0;
    private boolean autVyber, copyFrom=false;//, firstDraw=false;
    
    private BufferedImage bufImage = null;//, bufCopyFrom = null;
    //private Dimension vel;
    private Rectangle vel; 
    Paint paintBack;
    private ObrazecListener obrazecListener = null;
    
    public ArrayList<Hladina> hladina;
    public HladinaEdit hladinaEdit;
    Hladina dragHladina;
   
    public int mod;
    //AudioClip zvukHotovo;
    public Obrazec(Skladacka s, Paint pb, ArrayList<Hladina> h, int mod) {
        this(s, pb, h, null, null, null, null);
        this.mod = mod;
    }
    public Obrazec(Skladacka s, Paint pb, ArrayList<Hladina> h, HladinaEdit he, Dilek de[], Dilek du[], Obrys ou) {
        this();
        skladacka = s;
        hladina = h;

        vel = new Rectangle(0, 0, getWidth(), getHeight()); //getInsideRect(null); // new
        //Rectangle r = new Rectangle(0, 0, vel.width, vel.height);
        for(int i=0; i<hladina.size(); i++){
            hladina.get(i).setObrazec(this);
            //hladina.get(i).resize(r); // new
            hladina.get(i).resize(vel); // new
        }
        d = de;
        dNahled = du;
        o = ou;
        hladinaEdit = he;
        mod = hladinaEdit == null ? MOD_SHOW : MOD_EDIT;
        paintBack = pb;
    }
    public Obrazec() {
        
        addMouseListener(this);
        addMouseMotionListener(this);
        addMouseWheelListener(this);
        addKeyListener(this);
        
        setDoubleBuffered(false);
        setFocusable(true);
    }
    public Rectangle getInsideRect(Rectangle out){
        if(out == null){
            Dimension dim = getSize();
            out = new Rectangle(0,0,dim.width,dim.height);
        }
        Insets okr = getInsets();
        if(okr != null){
            out.x += okr.left;
            out.y += okr.top;
            out.width -= (okr.left + okr.right);
            out.height -= (okr.top + okr.bottom);
        }
        return out;
    }
    
    private void prepareBuffer() {
        vel = new Rectangle(0, 0, getWidth(), getHeight()); //getInsideRect(null);
        bufImage = new BufferedImage(vel.width,vel.height,BufferedImage.TYPE_INT_RGB);//gc.createCompatibleImage(vel.width, vel.height);
        rectUpdate.setBounds(vel);
        
        //Rectangle r = new Rectangle(vel.x, vel.y, vel.width, vel.height);
        //Rectangle r = new Rectangle(0, 0, vel.width, vel.height);
        for(Hladina h: hladina)
            h.resize(vel);
    }
    
    protected int addHladina(Hladina hn){
        hn.setObrazec(this);
        hn.resize(vel);
        hladina.add(hn);
        return hladina.size();
    }
  
    public void repaint(Obrazec obr){
        //TODO i stejn� r�me�ek?
        if(obr!=null && bufImage!= null && obr.bufImage.getWidth()==bufImage.getWidth() && obr.bufImage.getHeight()== bufImage.getHeight()){
            copyFrom = true;
            Graphics2D bufGraphic = bufImage.createGraphics();
            bufGraphic.drawImage(obr.bufImage, vel.x, vel.y, this);//BOR
            bufGraphic.dispose();
        }
        //else
        update(); //copy from je true, takze update se zbavi cekajicich prekresleni a paint je vykresli z bufferu do obrazce
        //bufCopyFrom = obr.bufImage;
    }
    
    public void update(){
        if(bufImage == null)
            return;
        for(Hladina h: hladina)
            h.validate();
        if(!rectUpdate.isEmpty()){
            rectUpdate.grow(15, 15);
            paintImmediately(rectUpdate);//??? zvazit, nestacil by repaint(rectUpdate)
        }
    }
    
    @Override
    public void paint(Graphics g) {
        //if(bufImage == null || bufImage.getWidth() != getWidth() || bufImage.getHeight()!= getHeight()){
        if(bufImage == null || bufImage.getWidth() != getWidth() || bufImage.getHeight()!= getHeight()){
            prepareBuffer();
            for(Hladina h: hladina)
                h.validate();
        }
        if(copyFrom == false) {
            if (!rectUpdate.isEmpty()) {
                Graphics2D bufGraphic = bufImage.createGraphics();
                bufGraphic.setClip(rectUpdate);
                bufGraphic.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                if (paintBack != null) { //TODO ??
                    bufGraphic.setPaint(paintBack);
                    bufGraphic.fill(vel);
                }
                for(Hladina h: hladina){
                    h.clear(bufGraphic);
                    h.draw(bufGraphic);
                }
                bufGraphic.dispose();
            }
        }
        else {
            copyFrom = false;
        }
        rectUpdate.setBounds(0, 0, 0, 0);
        g.drawImage(bufImage, vel.x, vel.y, null); //clipping zaridi orez
        this.paintBorder(g);
    }
    
    public void vyberVse(boolean jak) {
        vybrano = Dilek.vyberVse(d, jak);
        setPivot();
        update();
    }
    
    private void setPivot() {
        if (vybrano == 0)
            return;
        pivot.setLocation(0, 0);
        //TODO u vyberu vice dilku jako pivot stred bounding boxu ???? ale ten se otacenim meni
        for(Dilek dSel: d)
            if (dSel.jeVybran())
                pivot.translate(dSel.getPivot());
        pivot.x /= vybrano;
        pivot.y /= vybrano;
    }
    
    private void setPivot(double x, double y) {
        if (vybrano == 0)
            return;
        Point2D p = new Point2D(Skladacka.MAXCOORD, Skladacka.MAXCOORD);
        pivot.setLocation(x, y);
        for(Dilek dSel: d)
            if (dSel.jeVybran())
                dSel.getNearestPoint(pivot,p,true);
        pivot.translate(p);
    }
    
    private void bringToTop(Dilek di){
        Poloha pdi = di.getPoloha();
        if (pdi.zOrder == (d.length - 1))
            return;
        for(Dilek dil: d){
            if (dil.getPoloha().zOrder > pdi.zOrder)
                dil.changeZOrder(-1);
        }
        di.setZOrder(d.length - 1);
        Dilek.copyFrom(dNahled,d);//TODO zvazit
    }
    boolean vyber(double x, double y) {
        if(hladinaEdit.getVzhled() != Hladina.VZHLED_DILKY)
            return false;
        hladinaEdit.transformPoint(x, y, drag);
        Dilek dClicked = hladinaEdit.getDilekFromPoint(drag);
        if(dClicked != null){
            int sel = dClicked.invertujVyber();
            vybrano += sel;
            if (sel == 1) {
                bringToTop(dClicked);
            }
            update();
            setPivot();
            return true;
        }
        return false;
    }
    
    public void vycentruj() {
        Dilek.vycentruj(d);
        Dilek.copyFrom(dNahled,d); //TODO ??
        if(obrazecListener != null)
            obrazecListener.changed();
        o.update();
        update();
    }
    
    private boolean posunVyber(Point2D p){
        return posunVyber(p.x,p.y);
    }
    
    private boolean posunVyber(double x, double y) {
        if(x==0 && y==0)
            return false;
        
        pivot.x+=x;
        pivot.y+=y;
        
        for(Dilek dSel: d)
            if(dSel.jeVybran())
                dSel.posun(x, y);
        return true;
    }
    
    private boolean initDrag(int typ, int x, int y) {
        hladinaEdit.transformPoint(x,y,drag);
        if(hladinaEdit.getVzhled()==Hladina.VZHLED_DILKY){
            Dilek dClicked = hladinaEdit.getDilekFromPoint(drag);
            
            if (dClicked == null) {
                if (typ == POHYB_POSUN)
                    vyberVse(vybrano == 0 ? true : false);
                if(typ != POHYB_ROTACE_WHEEL || vybrano == 0)
                    return false;
            }
            else if (!dClicked.jeVybran()) {
                vyberVse(false);
                vybrano += dClicked.vyber(true);
                bringToTop(dClicked);
                //update();
                //dOrdered = Dilek.getOrdered(d);
                autVyber = true;
            }
        }
        else
            if (hladinaEdit.getObrysFromPoint(drag)==null)
                if(typ != POHYB_ROTACE_WHEEL)
                    return false;
        
        if(typ!=POHYB_ROTACE)
            setPivot();
        else
            setPivot(drag.getX(),drag.getY());
        pohyb = typ;
        setCursor(cur[pohyb]);

        hladinaEdit.suspend();
        update();
        
        last.setLocation(x,y);
        return true;
    }
    
    private boolean priskocVyber(){
        Point2D ret=new Point2D(skladacka.TOLERANCE_PRISKOK,skladacka.TOLERANCE_PRISKOK);
        for(Dilek dSel: d)
            if(dSel.jeVybran())
                for(Dilek dNotSel: d)
                    if(!dNotSel.jeVybran())
                        dSel.getVectNearest(dNotSel,ret,false);
        if(ret.distance(0,0)<skladacka.TOLERANCE_PRISKOK){
            posunVyber(ret);
            return true;
        }
        return false;
    }
    
    private boolean priskocVyberStrana(){
        Point2D ret = new Point2D(skladacka.TOLERANCE_PRISKOK,skladacka.TOLERANCE_PRISKOK), ret2 = new Point2D(ret);
        for(Dilek dSel: d)
            if(dSel.jeVybran())
                for(Dilek dNotSel: d)
                    if(!dNotSel.jeVybran())
                        dSel.getVectNearestSide(dNotSel,ret,ret2);
        Vect.negative(ret2);
        Vect.kratsiVect(ret,ret2);
        if(ret.distance(0,0)<skladacka.TOLERANCE_PRISKOK){
            posunVyber(ret);
            return true;
        }
        return false;
    }
    
    private Point2D vectToDveStrany(Point2D pbod, Point2D pret, Point2D[] pstr, Point2D bod, Point2D ret, Point2D[] str, boolean neg){
        //pxx nehybe se, xx priskakuje
        if(pbod.distanceSq(bod) == 0.0)
            return null;
        if(Math.abs(pret.x/ret.x - pret.y/ret.y)<Obrys.TOLERANCE_AREA)
            return null;
        Point2D pp = Vect.add(pbod, ret);
        Point2D qq = Vect.intersection(pp, Vect.add(pp, Vect.vect(str[0], str[1])), pstr[0], pstr[1], false);
        if(pp == null || qq == null)
            return null;
        Point2D vret = Vect.vect(pbod, qq);
        if(neg)
            Vect.negative(vret);
        if(mimoStranu(pbod, pstr, vret) || mimoStranu(bod, str, vret))
            return null;
        return vret;
    }
    private boolean mimoStranu(Point2D pbod, Point2D[] pstr, Point2D ret){
        Point2D nbod = new Point2D(pbod);
        nbod.translate(ret);
        double strlen = pstr[0].distance(pstr[1]);
        if(nbod.distance(pstr[0])>strlen || nbod.distance(pstr[1])>strlen)
            return true;
        return false;
    }
    private Point2D vectToDveStranyMix(Point2D pbod, Point2D pret, Point2D[] pstr, Point2D bod, Point2D ret, Point2D[] str){
        //pxx nehybe se, xx priskakuje
        if(pbod.distanceSq(bod) == 0.0)
            return null;
        if(Math.abs(pret.x/ret.x - pret.y/ret.y)<Obrys.TOLERANCE_AREA)
            return null;
        Point2D pp = Vect.sub(bod, pret);
        Point2D qq = Vect.intersection(pp, Vect.add(pp, Vect.vect(pstr[0], pstr[1])), str[0], str[1], false);
        if(pp == null || qq == null)
            return null;
        Point2D vret = Vect.vect(bod, qq);
        if(mimoStranu(pbod, pstr, Vect.getNegative(vret)) || mimoStranu(bod, str, vret))
            return null;
        return vret;
    }

    private int kratsiPriskok(Point2D x, Point2D y, int puvktery, int ktery){
        if(x != null && y != null){
            if(Vect.kratsiVect(x, y))
                return ktery;
        }
        else if (y != null){
            x.copyFrom(y);
            return ktery;
        }
        return puvktery;
    }
    
    private boolean priskocVyberDveStrany(){
        Point2D ret = new Point2D(skladacka.TOLERANCE_PRISKOK,skladacka.TOLERANCE_PRISKOK), ret2 = new Point2D(ret);
        Point2D pret = new Point2D(ret), pret2 = new Point2D(ret);
        Point2D pbod = new Point2D(ret), pbod2  = new Point2D(ret), bod = new Point2D(ret), bod2  = new Point2D(ret);
        Point2D[] str = new Point2D[2], pstr = new Point2D[2], str2 = new Point2D[2], pstr2 = new Point2D[2];
        for(Dilek dSel: d)
            if(dSel.jeVybran())
                for(Dilek dNotSel: d)
                    if(!dNotSel.jeVybran())
                        dSel.getVectNearestTwoSides(dNotSel, pbod, pret, pstr, bod, ret, str, pbod2, pret2, pstr2, bod2, ret2, str2);
        //Vect.negative(pret2); Vect.negative(ret2);
        Point2D x = new Point2D(Double.MAX_VALUE, Double.MAX_VALUE), y = null;
        final double T = skladacka.TOLERANCE_PRISKOK;
        int ktery = 0;
        if(ret.distance(0,0)<T && pret.distance(0,0)<T){
            y = vectToDveStrany(pbod, pret, pstr, bod, ret, str, false);
            ktery = kratsiPriskok(x, y, ktery, 1);
        }
        if(ret2.distance(0,0)<T && pret2.distance(0,0)<T){
            y = vectToDveStrany(pbod2, pret2, pstr2, bod2, ret2, str2, true);
            ktery = kratsiPriskok(x, y, ktery, 2);
        }
        if(ret.distance(0,0)<T && pret2.distance(0,0)<T){
            y = vectToDveStranyMix(pbod2, pret2, pstr2, bod, ret, str);
            ktery = kratsiPriskok(x, y, ktery, 3);
        }
        if(ret2.distance(0,0)<T && pret.distance(0,0)<T){
            y = vectToDveStranyMix(bod2, ret2, str2, pbod, pret, pstr);
            ktery = kratsiPriskok(x, y, ktery, 4);
        }
        if(ret.distance(0,0)<T && ret2.distance(0,0)<T){
            y = vectToDveStranyMix(bod2, ret2, str2, bod, ret, str);
            ktery = kratsiPriskok(x, y, ktery, 5);
        }
        if(pret.distance(0,0)<T && pret2.distance(0,0)<T){
            y = vectToDveStranyMix(pbod2,pret2, pstr2, pbod, pret, pstr);
            ktery = kratsiPriskok(x, y, ktery, 6);
        }
        if(x.x < Double.MAX_VALUE){
            posunVyber(x);
            return true;
        }
        return false;
    }
    
    private void endDrag() {
        if(pohyb == POHYB_FLIP)
            flipVyber();
        
        retToOut();
        
        if ((pohyb != POHYB_ROTACE_WHEEL && vybrano != d.length) && (autVyber || hladinaEdit.vzhled == HladinaEdit.VZHLED_OBRYS))
            vyberVse(false);
        
        autVyber = false;
        pohyb = POHYB_NIC;
        setCursor(cur[pohyb]);
        
        Dilek.copyFrom(dNahled,d);
        o.update();
        hladinaEdit.suspend();
        if(obrazecListener != null)
            obrazecListener.changed();
        update();
    }
    
    boolean drag(int x, int y) {
        hladinaEdit.transformPoint(last.x, last.y, drag);
        double xpuv = drag.getX(), ypuv = drag.getY();
        hladinaEdit.transformPoint(x, y, drag);
        posunVyber(drag.getX() - xpuv, drag.getY() - ypuv);
        update();
        last.setLocation(x, y);
        return true;
    }
    
    private Point2D vectRet(Dimension d, Rectangle2D co) {
        Point2D p = new Point2D(0, 0);
        double tol = Obrys.TOLERANCE_AREA/2;
        if (co.getX() < tol)
            p.x = tol - co.getX();
        else if ( (co.getX() + co.getWidth()) > (d.width-tol))
            p.x = d.width - tol - co.getX() - co.getWidth();
        if (co.getY() < tol)
            p.y = tol - co.getY();
        else if ( (co.getY() + co.getHeight()) > (d.height-tol))
            p.y = d.height - tol - co.getY() - co.getHeight();
        return p;
    }
    
    private boolean retToOut() {
        if (vybrano == 0)
            return false;
        boolean pos = false;
        Rectangle2D r = Dilek.getBoundsAll(d,true);
        if ( (r.getWidth() > (Skladacka.MAXCOORD-Obrys.TOLERANCE_AREA)) || (r.getHeight() >  (Skladacka.MAXCOORD-Obrys.TOLERANCE_AREA))) {
            for (Dilek dil: d) {
                if (dil.jeVybran()) {
                    r = dil.getBounds2D();
                    dil.posun(vectRet(new Dimension(Skladacka.MAXCOORD,Skladacka.MAXCOORD), r));
                }
            }
        } else
            pos = posunVyber(vectRet(new Dimension(Skladacka.MAXCOORD,Skladacka.MAXCOORD), r));
        return pos;
    }
    boolean isRecentering = false;
    private boolean rotate(MouseEvent e) {
        Point p = e.getPoint();
        if(isRecentering && p.x == last.x && p.y == last.y)
            isRecentering = false;
        else if (Math.abs(p.y - last.y) > ROTACE_CITLIVOST) {
            otocVyberKrok((p.y - last.y >= 0) ? 1 : -1);
            try {
                Robot r = new Robot();
                Point offset = getLocationOnScreen();
                r.mouseMove(offset.x + last.x, offset.y + last.y);
                isRecentering = true;
            } catch (Exception ex) {
                last.setLocation(p);
            }
            //finally {last.setLocation(p);}
            update();
            return true;
        }
        return false;
    }
    
    private void addOtoceni(List<Double> a, int kroku, double[] uhly1, double[] uhly2){
        for (int k = 0; k < uhly1.length; k++) {
            for (int l = 0; l < uhly2.length; l++) {
                double da = uhly2[l] - uhly1[k];
                if (kroku > 0) {
                    if (da > 0)
                        a.add(da);
                    da += Math.PI;
                    if (da > 2 * Math.PI)
                        da -= 2 * Math.PI;
                    if (da > 0)
                        a.add(da);
                } else {
                    if (da < 0)
                        a.add(-da);
                    da -= Math.PI;
                    if (da < -2 * Math.PI)
                        da += 2 * Math.PI;
                    if (da < 0)
                        a.add(-da);
                }
            }
        }
    }
    
    public void otocVyberKrok(int kroku){
        if(kroku==0 || vybrano==0)
            return;
        if(!skladacka.SMART_ROTATION)
            otocVyber(kroku*skladacka.ROTACE_KROK);
        else{
            double uhly1 [], uhly2[], TOL = 0.0001;
            int nSides = 0, nSidesSel = 0;
            for(Dilek dSel: d){
                if (dSel.jeVybran())
                    nSidesSel += dSel.getSidesCount();
                else
                    nSides += dSel.getSidesCount();
            }
            double d2PI = 2*Math.PI;
            double uhlyKrok[]= new double[(int)Math.round(d2PI/skladacka.ROTACE_KROK)], lastKrok = 0;
            for(int i = 0; i < uhlyKrok.length; i++){
                uhlyKrok[i] = lastKrok;
                lastKrok += skladacka.ROTACE_KROK;
            }
            int cap = 2*nSidesSel*nSides + 2*nSidesSel*uhlyKrok.length;
            ArrayList<Double> a = new ArrayList<Double>(cap);
            for(Dilek dSel: d){
                if(dSel.jeVybran()){
                    //TODO ????
                	/*
                	Poloha p = dSel.getPoloha();
                	double dToKrok;
                    if(kroku > 0)
                        dToKrok = Math.ceil(p.otoceni / skladacka.ROTACE_KROK) * skladacka.ROTACE_KROK - p.otoceni;
                    else
                        dToKrok = p.otoceni - Math.floor(p.otoceni / skladacka.ROTACE_KROK) * skladacka.ROTACE_KROK;
                    */
                    uhly1 = dSel.getUhly();
                    addOtoceni(a, kroku, uhly1, uhlyKrok);
                    for(Dilek dNotSel: d){
                        if (!dNotSel.jeVybran()) {
                            uhly2 = dNotSel.getUhly();
                            addOtoceni(a, kroku, uhly1, uhly2);
                        }
                    }
                }
            }
            Double dif [] = new Double[a.size()];
            a.toArray(dif);
            Arrays.sort(dif);
            a = new ArrayList<Double>(cap);
            Double db = new Double(0);
            for(Double difi: dif){
                if (difi - db > TOL) {
                    db = difi;
                    a.add(db);
                } else if(a.size()>0){
                    a.remove(a.size()-1);
                    a.add(db);
                }
            }
            otocVyber((kroku < 0 ? -1 : 1) * a.get((Math.abs(kroku)-1)%a.size()));
        }
    }
    public void otocVyber(double a) {
        for(Dilek dSel: d)
            if(dSel.jeVybran())
                dSel.otoc(pivot,a);
    }
    
    public void flipVyber(){
        for(Dilek dSel: d)
            if(dSel.jeVybran())
                dSel.flip(pivot);
    }
    
    public Hladina getHladinaFromPoint(Point p){
        Hladina ret = null;
        for(int i = hladina.size()-1; i>=0; i--){
            ret = hladina.get(i);
            if(ret.contains(p))
                return ret;
        }
        return ret;
    }
    
    public void mousePressed(MouseEvent e) {
        /*if(hladinaEdit == null && obrazecListener != null){
            obrazecListener.mouseDown(e);
            if(e.isConsumed())
                return;
        }*/
        boolean consumed = false;
        if(mod == MOD_EDIT && hladinaEdit != null){
            switch (e.getButton()) {
                case MouseEvent.BUTTON1:
                    /*if(hladinaEdit == null){
                        if(obrazecListener != null)
                            obrazecListener.mouseDown(e);
                            break;
                    }*/
                    if(e.isAltDown() || e.getClickCount()>1)
                        initDrag(POHYB_FLIP, e.getX(), e.getY());
                    else
                        initDrag(POHYB_POSUN, e.getX(), e.getY());
                    consumed = true;
                    break;
                case MouseEvent.BUTTON2:
                    /*if(hladinaEdit == null){
                        if(obrazecListener != null)
                            obrazecListener.mouseDown(e);
                        break;
                    }*/
                    if(e.getClickCount()==1)
                        initDrag(POHYB_ROTACE, e.getX(), e.getY());
                    else
                        initDrag(POHYB_FLIP, e.getX(), e.getY());
                    consumed = true;
                    break;
                case MouseEvent.BUTTON3:
                    /*if (hladinaEdit==null || !vyber(e.getX(), e.getY())){
                        if(obrazecListener != null)
                            obrazecListener.mouseDown(e);
                    } else*/
                    if (vyber(e.getX(), e.getY())){
                        autVyber=false;
                        consumed = true;
                    }
            }
        }
        else if(mod == MOD_LAYOUT){
            if(e.getButton() == MouseEvent.BUTTON1){
                Point p = e.getPoint();
                Hladina h = getHladinaFromPoint(p);
                if(h != null){
                    pohyb = POHYB_HLADINA_POSUN;
                    last.setLocation(p);
                    dragHladina = h;
                    consumed = true;
                }
            }
        
        }
        if(consumed == false && obrazecListener != null)
            obrazecListener.mouseDown(e);
    }
    
    public void mouseReleased(MouseEvent e) {
        if(hladinaEdit == null)
            return;
        if(pohyb == POHYB_HLADINA_POSUN){
            pohyb = POHYB_NIC;
            return;
        }
        if (pohyb!=POHYB_NIC){
            if(pohyb == POHYB_POSUN){
                if (e.isControlDown())
                    priskocVyberStrana();
                else if (e.isAltDown())
                    priskocVyberDveStrany();
                else if (!e.isShiftDown())
                    priskocVyber();
            }
            endDrag();
        }
    }
    
    public void mouseDragged(MouseEvent e) {
        if(pohyb==POHYB_POSUN)
            drag(e.getX(),e.getY());
        else if(pohyb==POHYB_ROTACE)
            rotate(e);
        else if(pohyb==POHYB_HLADINA_POSUN){
            int dx = e.getX() - last.x;
            int dy = e.getY() - last.y;
            dragHladina.invalidate();
            dragHladina.pos.translate(dx, dy);
            dragHladina.resize();
            dragHladina.invalidate();
            //dragHladina.add
            paintImmediately(rectUpdate);
            last.setLocation(e.getPoint());
        }
    }
    
    public void mouseWheelMoved(MouseWheelEvent e) {
        if(hladinaEdit == null)
            return;
        if (initDrag(POHYB_ROTACE_WHEEL, e.getX(), e.getY())) {
            otocVyberKrok(e.getWheelRotation());
            endDrag();
        }
    }
    public void keyTyped(KeyEvent e){  }
    public void keyReleased(KeyEvent e){  }
    
    public void keyPressed(KeyEvent e){
        if(hladinaEdit != null){
            if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                flipVyber();
                retToOut();
                Dilek.copyFrom(dNahled,d);
                o.update();
                update();
            } else if (e.getKeyCode() == KeyEvent.VK_C){
                vycentruj();
                //update();
            }
        }
        if(obrazecListener != null)
            obrazecListener.keyDown(e);
    }
    public void prepniVzhled(){
        if(hladinaEdit==null)
            return;
        vyberVse(hladinaEdit.prepniVzhled()==Hladina.VZHLED_OBRYS);
    }
    
    public void setHladinaEdit(HladinaEdit he){
        hladinaEdit = he;
        mod = hladinaEdit == null ? MOD_SHOW : MOD_EDIT; //TODO Layout?
    }
    public void setSkladacka(Skladacka s, Dilek newd[], Dilek newdNahled[], Obrys newo){
        skladacka = s;
        if(hladinaEdit != null){
            dNahled = skladacka.getDilky();
            d = newd;
            dNahled = newdNahled;
            o = newo;
            vybrano = 0;
            for(Dilek dSel: d)
                if(dSel.jeVybran())
                    vybrano++;
            hladinaEdit.update(d, o);
        }
    }
    
    public void mouseEntered(MouseEvent e) { }
    public void mouseMoved(MouseEvent e) { }
    
    public void mouseClicked(MouseEvent e) {
        if(e.getClickCount() > 1 && obrazecListener != null)
            obrazecListener.mouseDown(e);
    }
    public void mouseExited(MouseEvent parm1) { }
    public void addObrazecListener(ObrazecListener ol){
        obrazecListener = ol;
    };
    public void update(Graphics2D g){
        rectUpdate.setRect(vel.x, vel.y, vel.width, vel.height);
        paint(g);
    }
    
    @Override
    public void print(Graphics g){
        Graphics2D g2 = (Graphics2D)g;
        for (Hladina h: hladina){
            h.clear(g2);
            h.draw(g2);
        }
    }
}
